package cn.iocoder.yudao.module.dify.util;

import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;
import java.util.HashSet;
import java.util.Set;

/**
 * DOC 转 DOCX 工具类
 * 使用 Apache POI 的 poi-scratchpad 和 poi-ooxml 模块实现转换
 * 支持文本、段落样式和表格转换
 */
public class DocToDocxConverter {

    public static void main(String[] args) {
        try {
            // 使用完整转换方法
            File docFile = new File("D:\\puyuanTestData\\法规问答\\医疗器械经营企业自查要点.doc");
            File docxFile = new File("D:\\puyuanTestData\\法规问答\\医疗器械经营企业自查要点4.docx");
            DocToDocxConverter.convertDocToDocx(docFile, docxFile);
            System.out.println("DOC 转 DOCX 完成");

            // 或使用简化方法
            DocToDocxConverter.simpleConvert("D:\\puyuanTestData\\法规问答\\医疗器械经营企业自查要点.doc", "D:\\puyuanTestData\\法规问答\\医疗器械经营企业自查要点5.docx");
            System.out.println("简化转换完成");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将 DOC 文件转换为 DOCX 文件
     *
     * @param docFile  DOC 文件
     * @param docxFile 转换后的 DOCX 文件
     * @throws IOException IO异常
     */
    public static void convertDocToDocx(File docFile, File docxFile) throws IOException {
        FileInputStream fis = null;
        HWPFDocument hwpfDocument = null;
        XWPFDocument xwpfDocument = null;
        FileOutputStream fos = null;

        try {
            // 读取 DOC 文件
            fis = new FileInputStream(docFile);
            hwpfDocument = new HWPFDocument(fis);

            // 创建新的 DOCX 文档
            xwpfDocument = new XWPFDocument();

            // 转换内容
            convertContent(hwpfDocument, xwpfDocument);

            // 保存 DOCX 文件
            fos = new FileOutputStream(docxFile);
            xwpfDocument.write(fos);

        } finally {
            closeQuietly(fis);
            closeQuietly(hwpfDocument);
            closeQuietly(xwpfDocument);
            closeQuietly(fos);
        }
    }

    /**
     * 转换文档内容
     *
     * @param hwpfDocument 原始 DOC 文档
     * @param xwpfDocument 目标 DOCX 文档
     */
    private static void convertContent(HWPFDocument hwpfDocument, XWPFDocument xwpfDocument) {
        // 获取文档范围
        Range range = hwpfDocument.getRange();

        // 记录已处理的表格起始位置，避免重复处理
        Set<Integer> processedTableStarts = new HashSet<>();

        // 处理段落
        for (int i = 0; i < range.numParagraphs(); i++) {
            Paragraph paragraph = range.getParagraph(i);
            // 处理过的不用重复处理
            int tableStartOffset = paragraph.getStartOffset();
            // 检查是否在表格中
            if (paragraph.isInTable()) {
                // 如果该表格尚未处理，则处理表格
                if (!processedTableStarts.contains(tableStartOffset)) {
                    try {
                        // 获取表格
                        Table table = range.getTable(paragraph);
                        if (table != null) {
                            convertTable(table, xwpfDocument);
                            // 记录表格起始位置，避免重复处理
                            processedTableStarts.add(tableStartOffset);
                        } else {
                            // 表格为空，当作普通段落处理
                            convertNormalParagraph(paragraph, xwpfDocument);
                        }
                    } catch (Exception e) {
                        // 表格处理失败，当作普通段落处理
//                        if (!processedTableStarts.contains(tableStartOffset)) {
//                            convertNormalParagraph(paragraph, xwpfDocument);
//                        }
                    }
                }
                // 如果表格已处理过，则跳过当前段落（它是表格的一部分）
            } else {
                // 普通段落处理
                if (!processedTableStarts.contains(tableStartOffset)) {
                    convertNormalParagraph(paragraph, xwpfDocument);
                }

            }
        }
    }

    /**
     * 改进的表格索引获取方法
     *
     * @param paragraph 段落
     * @return 表格索引
     */
    private static int getTableIndex(Paragraph paragraph) {
        // 使用段落的起始位置作为表格标识，更加可靠
        return paragraph.getStartOffset();
    }


    /**
     * 转换普通段落
     *
     * @param paragraph    原始段落
     * @param xwpfDocument 目标文档
     */
    private static void convertNormalParagraph(Paragraph paragraph, XWPFDocument xwpfDocument) {
        // 创建新的段落
        XWPFParagraph xwpfParagraph = xwpfDocument.createParagraph();

        // 设置段落样式
        setParagraphStyle(paragraph, xwpfParagraph);

        // 处理段落中的文本运行
        for (int j = 0; j < paragraph.numCharacterRuns(); j++) {
            CharacterRun characterRun = paragraph.getCharacterRun(j);
            convertCharacterRun(characterRun, xwpfParagraph);
        }
    }

    /**
     * 转换单个表格
     *
     * @param table        原始表格
     * @param xwpfDocument 目标文档
     */
    private static void convertTable(Table table, XWPFDocument xwpfDocument) {
        try {
            if (table == null) {
                return;
            }

            // 创建新的表格
            int numRows = table.numRows();
            if (numRows <= 0) {
                return;
            }

            // 获取最大列数
            int maxCols = getMaxColumns(table);
            if (maxCols <= 0) {
                maxCols = 1;
            }

            // 创建表格
            XWPFTable xwpfTable = xwpfDocument.createTable(numRows, maxCols);

            // 转换表格行和单元格
            for (int i = 0; i < numRows; i++) {
                TableRow row = table.getRow(i);
                if (row != null && i < xwpfTable.getRows().size()) {
                    XWPFTableRow xwpfRow = xwpfTable.getRow(i);
                    convertTableRow(row, xwpfRow);
                }
            }
        } catch (Exception e) {
            // 表格转换失败，输出错误信息但不中断程序
            System.err.println("表格转换失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 获取表格的最大列数
     *
     * @param table 原始表格
     * @return 最大列数
     */
    private static int getMaxColumns(Table table) {
        int maxColumns = 0;
        for (int i = 0; i < table.numRows(); i++) {
            TableRow row = table.getRow(i);
            if (row != null) {
                maxColumns = Math.max(maxColumns, row.numCells());
            }
        }
        return maxColumns;
    }

    /**
     * 转换表格行
     *
     * @param row     原始行
     * @param xwpfRow 目标行
     */
    private static void convertTableRow(TableRow row, XWPFTableRow xwpfRow) {
        try {
            // 转换行中的单元格
            for (int j = 0; j < row.numCells(); j++) {
                TableCell cell = row.getCell(j);
                if (cell != null && j < xwpfRow.getTableCells().size()) {
                    XWPFTableCell xwpfCell = xwpfRow.getCell(j);
                    convertTableCell(cell, xwpfCell);
                }
            }
        } catch (Exception e) {
            // 忽略行转换错误
            System.err.println("行转换失败: " + e.getMessage());
        }
    }

    /**
     * 转换单元格
     *
     * @param cell     原始单元格
     * @param xwpfCell 目标单元格
     */
    private static void convertTableCell(TableCell cell, XWPFTableCell xwpfCell) {
        try {
            // 清空默认段落
            if (!xwpfCell.getParagraphs().isEmpty()) {
                xwpfCell.removeParagraph(0);
            }

            // 处理单元格中的段落
            for (int i = 0; i < cell.numParagraphs(); i++) {
                Paragraph paragraph = cell.getParagraph(i);
                if (paragraph != null) {
                    XWPFParagraph xwpfParagraph = xwpfCell.addParagraph();
                    setParagraphStyle(paragraph, xwpfParagraph);

                    // 处理段落中的文本运行
                    for (int j = 0; j < paragraph.numCharacterRuns(); j++) {
                        CharacterRun characterRun = paragraph.getCharacterRun(j);
                        convertCharacterRun(characterRun, xwpfParagraph);
                    }
                }
            }
        } catch (Exception e) {
            // 忽略单元格转换错误
            System.err.println("单元格转换失败: " + e.getMessage());
        }
    }

    /**
     * 设置段落样式
     *
     * @param paragraph     原始段落
     * @param xwpfParagraph 目标段落
     */
    private static void setParagraphStyle(Paragraph paragraph, XWPFParagraph xwpfParagraph) {
        // 设置对齐方式
        try {
            switch (paragraph.getLvl()) {
                case 1:
                    xwpfParagraph.setAlignment(ParagraphAlignment.CENTER);
                    break;
                case 2:
                    xwpfParagraph.setAlignment(ParagraphAlignment.RIGHT);
                    break;
                default:
                    xwpfParagraph.setAlignment(ParagraphAlignment.LEFT);
                    break;
            }
        } catch (Exception e) {
            // 忽略样式设置错误
        }

        // 设置缩进
        try {
            xwpfParagraph.setIndentationLeft(paragraph.getIndentFromLeft());
            xwpfParagraph.setIndentationRight(paragraph.getIndentFromRight());
            xwpfParagraph.setIndentationFirstLine(paragraph.getFirstLineIndent());
        } catch (Exception e) {
            // 忽略缩进设置错误
        }
    }

    /**
     * 转换字符运行（文本样式）
     *
     * @param characterRun  原始字符运行
     * @param xwpfParagraph 目标段落
     */
    private static void convertCharacterRun(CharacterRun characterRun, XWPFParagraph xwpfParagraph) {
        try {
            XWPFRun xwpfRun = xwpfParagraph.createRun();

            // 设置文本内容
            String text = characterRun.text();
            if (text != null) {
                xwpfRun.setText(text);
            }

            // 设置字体样式
            setRunStyle(characterRun, xwpfRun);
        } catch (Exception e) {
            // 忽略运行设置错误
            System.err.println("字符运行转换失败: " + e.getMessage());
        }
    }

    /**
     * 设置文本运行样式
     *
     * @param characterRun 原始字符运行
     * @param xwpfRun      目标运行
     */
    private static void setRunStyle(CharacterRun characterRun, XWPFRun xwpfRun) {
        try {
            // 设置字体大小（以半点为单位，需要转换为磅）
            int fontSize = characterRun.getFontSize();
            if (fontSize != -1) {
                xwpfRun.setFontSize(fontSize / 2);
            }

            // 设置粗体
            if (characterRun.isBold()) {
                xwpfRun.setBold(true);
            }

            // 设置斜体
            if (characterRun.isItalic()) {
                xwpfRun.setItalic(true);
            }

            // 设置下划线
            if (characterRun.getUnderlineCode() != 0) {
                xwpfRun.setUnderline(UnderlinePatterns.SINGLE);
            }

            // 设置删除线
            if (characterRun.isStrikeThrough()) {
                xwpfRun.setStrike(true);
            }

            // 设置字体颜色（修复：确保颜色值是有效的十六进制格式）
            int color = characterRun.getColor();
            if (color >= 0) {
                // 将颜色值转换为十六进制字符串并确保格式正确
                String hexColor = String.format("%06X", color);
                // 验证是否为有效的十六进制颜色值
                if (isValidHexColor(hexColor)) {
                    xwpfRun.setColor(hexColor);
                }
            }

            // 设置字体名称
            String fontName = characterRun.getFontName();
            if (fontName != null && !fontName.isEmpty()) {
                xwpfRun.setFontFamily(fontName);
            }
        } catch (Exception e) {
            // 忽略样式设置错误
            System.err.println("样式设置失败: " + e.getMessage());
        }
    }

    /**
     * 验证是否为有效的十六进制颜色值
     *
     * @param hexColor 十六进制颜色值
     * @return 是否有效
     */
    private static boolean isValidHexColor(String hexColor) {
        if (hexColor == null || hexColor.length() != 6) {
            return false;
        }
        // 检查是否只包含十六进制字符
        return hexColor.matches("[0-9A-F]+");
    }

    /**
     * 静默关闭 Closeable 资源
     *
     * @param closeable 待关闭的资源
     */
    private static void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                // 忽略关闭异常
            }
        }
    }

    /**
     * 简化版本的 DOC 转 DOCX 方法
     *
     * @param docFilePath  DOC 文件路径
     * @param docxFilePath 转换后的 DOCX 文件路径
     * @throws IOException IO异常
     */
    public static void simpleConvert(String docFilePath, String docxFilePath) throws IOException {
        try (FileInputStream fis = new FileInputStream(docFilePath);
             HWPFDocument doc = new HWPFDocument(fis);
             XWPFDocument docx = new XWPFDocument();
             FileOutputStream fos = new FileOutputStream(docxFilePath)) {

            // 提取文本内容
            WordExtractor extractor = new WordExtractor(doc);
            String[] paragraphs = extractor.getParagraphText();

            // 将文本内容写入新的 DOCX 文档
            for (String paragraphText : paragraphs) {
                XWPFParagraph paragraph = docx.createParagraph();
                XWPFRun run = paragraph.createRun();
                run.setText(paragraphText);
            }

            // 保存 DOCX 文件
            docx.write(fos);
        }
    }
}
